//
//  OPBaseObject.m
//  OPFramework
//
//  Created by malcom on 7/12/08.
//  Copyright 2008 __MyCompanyName__. All rights reserved.
//

#import "OPBaseObject.h"
#import "OPBoard.h"


@implementation OPBaseObject

@synthesize _delegateBoard;
@synthesize _lastResponse;
@synthesize _lastUpdate;
@synthesize _lastErrorCode;
@synthesize _asyncModeActive;

- (id) init {
	self = [super init];
	if (self != nil) {
		_lastUpdate = nil;
		_listeners = [[NSMutableArray alloc] init];
		_asyncModeActive = NO;
	}
	return self;
}

- (id) initWithBoard:(OPBoard *) _board andListener:( NSObject <OPObject_AsyncResponse> *) _listener {
	self = [super init];
	if (self != nil) {
		_lastUpdate = nil;
		_listeners = [[NSMutableArray alloc] initWithObjects: _listener,nil];
		_delegateBoard = [_board retain];
		_asyncModeActive = _delegateBoard._config_workAsAsync;
	}
	return self;
}


- (id) initWithBoard:(OPBoard *) _board { 
	self = [super init];
	if (self != nil) {
		_lastUpdate = nil;
		_listeners = [[NSMutableArray alloc] init];
		_delegateBoard = [_board retain];
		_asyncModeActive = _delegateBoard._config_workAsAsync;
	}
	return self;
}

- (BOOL) loadData { return NO; }

- (BOOL) dataAvailable {
	return (_lastUpdate != nil);
}

- (void) addObjectAsListenerForMe:(NSObject <OPObject_AsyncResponse>*) _resp {
	[_listeners addObject: _resp];
	NSLog(@"%d listener added (%@) for %@",[_listeners count],[_resp className],[self className]);
}

- (void) dataUpdatedFor:(OPBaseObject *) _obj atMethod:(NSString *) _method {
	// we can update the cache last update date
	if (_lastUpdate != nil) [_lastUpdate release];
	_lastUpdate = [[NSDate date] retain];
	
	// after we can alert listeners
	for (NSObject <OPObject_AsyncResponse> *cObj in _listeners)
		[cObj dataUpdatedFor: _obj atMethod: _method];
}

- (void) errorReceivedForDataUpdate:(NSNumber *) _errorCode from:(OPBaseObject *) _obj {
	// after we can alert listeners
	for (NSObject <OPObject_AsyncResponse> *cObj in _listeners)
		[cObj errorReceivedForDataUpdate: _errorCode from: _obj];
}

- (void) serverErrorForDataUpdateFrom:(OPBaseObject *) _obj error:(NSDictionary *) _dict {
	// after we can alert listeners
	for (NSObject <OPObject_AsyncResponse> *cObj in _listeners)
		[cObj serverErrorForDataUpdateFrom: _obj error: _dict];
}

- (BOOL) isCacheExpired {
	if (_lastUpdate == nil) return YES; // never updated
	
	NSTimeInterval lastUpdate = [_lastUpdate timeIntervalSince1970];
	NSTimeInterval now = [[NSDate date] timeIntervalSince1970];
	BOOL exp = ( (now - lastUpdate) > _delegateBoard._config_cacheValidTime);
	return exp;
}

- (void) dealloc {
	[_delegateBoard release];
	[_lastUpdate release];
	[_listeners release];
	[super dealloc];
}

- (void) sendXMLRequestForMethod:(NSString *) _methodName withParams:(NSArray *) _params parseSelector:(SEL) _parseSel {
	[self sendXMLRequestForMethod: _methodName withParams:_params parseSelector:_parseSel forceSyncRequest: NO];
}

- (BOOL) sendXMLRequestForMethod:(NSString *) _methodName withParams:(NSArray *) _params parseSelector:(SEL) _parseSel forceSyncRequest:(BOOL) _sync {
	// we will make this request in main loop (synchronous mode)
	if (!_asyncModeActive || _sync) {
		// make the request in sync mode. After we get the result we will call parse method specified in _parseSel
		XMLRPCResponse *unansTopics = [_delegateBoard _executeRequestMethodNamed: _methodName
																	  withParams: _params
																  attachAuthData: NO];
		
		BOOL error = [self _checkErrorInRawResponseFromServer: unansTopics forMethod: _methodName];
		// if no error has occurred we can propagate the result for subclass parser
		if (error == NO) {
			[self performSelectorOnMainThread: _parseSel withObject:[NSArray arrayWithObjects: [unansTopics responseObject],_methodName,nil] waitUntilDone: YES];
			return YES;
		} else return NO; // something wrong has occurred
	} else {
		// we perform a background request (results will be available in -connection:didReceiveResponse:forMethod:)
 		[_delegateBoard _executeRequestMethodNamed: _methodName
										withParams:_params 
									attachAuthData: NO 
									 asyncResponse: self];
		return YES; // this is not valid when you perform an async request. it return always true
	}
}
	
- (void)connection: (XMLRPCConnection *)connection didReceiveResponse:(XMLRPCResponse *)response forMethod: (NSString *)method {
	
}
	
- (BOOL) _checkErrorInRawResponseFromServer:(XMLRPCResponse *) response forMethod:(NSString *) method {
	if (response != nil) {
		if (![response isFault]) {
			
			BOOL isAnError = NO;
			// if the response object is an NSNumber we should check if it's an error (only derivate class knows it. You should implement it in your subclass)
			if ([[response responseObject] isKindOfClass: [NSNumber class]]) {
				isAnError = [self _isNumericResponseFromServerAnErrorCode: (NSNumber *)[response responseObject] forMethod: method];
				
				// if it's not an error or simply the result is not an NSNumber response we can propagate it to the subclass parser choosed (sync mode)
				if (!isAnError)
					return NO;
				// otherwise we should propagate the error code
				else
					[self errorReceivedForDataUpdate: [response responseObject] from: self];
				
				return YES;
				// something goes wrong with your server connection or in ofapi... we simply report the error with some infos (faultString and faultCode in an NSDictionary)
			} else return NO;
		} else [self serverErrorForDataUpdateFrom: self error: [response responseObject]];
	}
	return YES;
}

- (BOOL) _isNumericResponseFromServerAnErrorCode:(NSNumber *) _code forMethod:(NSString *) method {
	return NO;					
}
	
- (void) refreshData {
	
}

- (void) setCacheAsExpired {
	[_lastUpdate release]; _lastUpdate = nil;
}

@end
